<?php

/**
 * Class DB
 * 数据库操作类
 */

/**
 * Class DB
 * 数据库操作类
 */
class pdodb2 {

    /**
     * @var
     * @return CDB
     */
    private static $db;

    /*     * 获取CDb类
     * @param $table_name 表名称
     * @param string $db_setting 调用数据库配置项
     * @param array $db_config 数据库配置
     * @return CDb
     */

    public static function cdb($table_name = '', $db_setting = 'default', $db_config = array()) {
        if (!isset(self::$db)) {
            $db = new CDb($table_name, $db_setting, $db_config);
            self::$db = $db;
        } else {
            $db = self::$db;
        }
        return $db;
    }

    /** 配置
     * @param $table_name 表名称
     * @param string $db_setting 调用数据库配置项
     * @param array $db_config 数据库配置
     * @return CDb
     */
    public static function init($table_name = '', $db_setting = 'default', $db_config = array()) {
        return self::cdb($table_name, $db_setting, $db_config);
    }

    /**
     * 执行删除记录操作
     * @param $table 表名称
     * @param $condition 	删除数据条件,不充许为空。可以为数组
     * @return boolean
     */
    public static function delete($table, $condition) {
        $db = self::cdb();
        $db->setTableName($table);
        return $db->delete($condition);
    }

    /**
     * 执行添加记录操作
     * @param $table 表名称
     * @param array $data 		要增加的数据，参数为数组。数组key为字段值，数组值为数据取值
     * @param bool $return_insert_id 是否返回新建ID号
     * @param bool $replace 是否采用 replace into的方式添加数据
     * @return boolean
     */
    public static function insert($table, $data, $return_insert_id = false, $replace = false) {
        $db = self::cdb();
        $db->setTableName($table);
        return $db->insert($data, $return_insert_id, $replace);
    }

    /**
     * 获取最后一次添加记录的主键号
     * @return int
     */
    public static function insertID() {
        $db = self::cdb();
        return $db->insert_id();
    }

    /**
     * 执行更新记录操作
     * @param $table 表名称
     * @param $data 		要更新的数据内容，参数为数组
     * 						为数组时数组key为字段值，数组值为数据取值
     * 						为数组时[例: array('name'=>'lanmps','password'=>'123456')]
     * 						数组的另一种使用array('name'=>'+=1', 'base'=>'-=1');程序会自动解析为`name` = `name` + 1, `base` = `base` - 1
     * 						字符串,请按照格式 ：
     * 						字符串 [例2：array('catid=:catid AND time>=:time ',array(':catid'=>10,':time'=>'2012-02-10')) ]
     * @param $where 		更新数据时的条件,
     * 						字符串,请按照格式 ：
     *                      字符串 [例1：" id=1 and time>$time " ]
     * 						字符串 [例2：array('catid=:catid AND time>=:time ',array(':catid'=>10,':time'=>'2012-02-10')) ]
     * 						数组时 [例: array('name'=>'lanmps','password'=>'123456')]
     * @return boolean
     */
    public static function update($table, $data, $where) {
        $db = self::cdb();
        $db->setTableName($table);
        return $db->update($data, $where);
    }

    /**
     * 获取单条记录查询
     * @param array $sql 		查询条件语句
     * @return array/null	数据查询结果集,如果不存在，则返回空
     */
    public static function fetchFirst($sql) {
        $db = self::cdb();
        return $db->fetch($sql);
    }

    /**
     * 执行sql查询
     * @param $sql 		查询条件
     * @return array	查询结果集数组
     */
    public static function fetchAll($sql) {
        $db = self::cdb();
        return $db->fetchAll($sql);
    }

    /**
     * 直接执行sql查询
     * @param $sql							查询sql语句
     * @return
     */
    public static function query($sql) {
        $db = self::cdb();
        return $db->exec($sql);
    }

    /**
     * 执行sql查询
     * @param $table 表名称
     * @param $where 		查询条件
     *   					字符串,请按照格式 ：
     *                      字符串 [例1：" id=1 and time>$time " ]
     * 						字符串 [例2：array('catid=:catid AND time>=:time ',array(':catid'=>10,':time'=>'2012-02-10')) ]
     * 						数组时 [例: array('name'=>'lanmps','password'=>'123456')]
     * @param $fields 		需要查询的字段值[例`name`,`gender`,`birthday`]
     * @param $limit 		返回结果范围[例：10或10,10 默认为空]
     * @param $order 		排序方式	[默认按数据库默认方式排序]
     * @param $group 		分组方式	[默认为空]
     * @return array		查询结果集数组
     */
    public static function select($table, $where = '', $fields = '*', $limit = '', $order = '', $group = '') {
        $db = self::cdb();
        $db->setTableName($table);
        return $db->select($where, $fields, $limit, $order, $group);
    }

    /**
     * 获取单条记录查询
     * @param $table 表名称
     * @param array $where 		查询条件语句
     *  					字符串,请按照格式 ：
     * 						字符串 [例2：array('catid=:catid AND time>=:time ',array(':catid'=>10,':time'=>'2012-02-10')) ]
     * 						数组时 [例: array('name'=>'lanmps','password'=>'123456')]
     * @param string $fields 		需要查询的字段值[例`name`,`gender`,`birthday`]
     * @param string $order 		排序方式	[默认按数据库默认方式排序]
     * @param string $group 		分组方式	[默认为空]
     * @return array/null	数据查询结果集,如果不存在，则返回空
     */
    public static function getOne($table, $where, $fields = '*', $order = '', $group = '') {
        $db = self::cdb();
        $db->setTableName($table);
        return $db->get_one($where, $fields, $order, $group);
    }

    /**
     * 查询多条数据并分页
     * @param $table 表名称
     * @param $where        查询条件
     *   					字符串,请按照格式 ：
     *                      字符串 [例1：" id=1 and time>$time " ]
     * 						字符串 [例2：array('catid=:catid AND time>=:time ',array(':catid'=>10,':time'=>'2012-02-10')) ]
     * 						数组时 [例: array('name'=>'lanmps','password'=>'123456')]
     * @param $fields       字段 *,id
     * @param $order        排序 id desc ,orderlist asc
     * @param $page         页码 1
     * @param $pagesize     每页条数
     * @return array('data'=>数据,'count'=>记录总数)
     */
    public static function listInfo($table, $where = '', $fields = '*', $order = '', $page = 1, $pagesize = 20) {
        $db = self::cdb();
        $db->setTableName($table);
        $d = $db->listinfo($where, $fields, $order, $page, $pagesize);
        return array('data' => $d, 'count' => self::$db->number);
    }

    /*     * 第一个参数值
     * @param $sql
     * @return mixed
     */

    public static function resultFirst($sql) {
        $db = self::cdb();
        return $db->resultFirst($sql);
    }

    public static function startTrans() {
        $db = self::cdb();
        return $db->beginTransaction();
    }
    
    public static function inTransaction() {
         $db = self::cdb();
        return $db->inTransaction();
    }

    public static function commit() {
        $db = self::cdb();
        return $db->commit();
    }

    public static function rollback() {
        $db = self::cdb();
        return $db->rollBack();
    }

    final public function table_exists($table) {
        $db = self::cdb();
        return $db->table_exists($table);
    }

}

/* * 错误函数 Feng.Fox
 * @param $e 对象
 * @param bool $debug
 * @param string $message 错误信息
 * @param string $sql 错误sQL
 * @return bool
 */

function halt($e, $debug = true, $message = '', $sql = '') {
    if ($debug) {
        if (isset($e->errorInfo)) {
            $errorInfo = $e->errorInfo;
            $errorno = $e->getCode();
            $error = $e->getMessage();
            $errorFile = $e->getFile();
            $errorLine = $e->getLiNe();
        } elseif ($e->getCode()) {
            $errorLine = $e->getLine();
            $errorno = $e->getCode();
            $error = $e->getMessage();
            $errorFile = $e->getFile();
        } else {
            $errorInfo = $e->errorInfo();
            $errorno = $errorInfo [1];
            $error = $errorInfo [2];
            $errorFile = '';
        }
        $errormsg = "<b>MySQL Query : </b> $sql <br /><b> MySQL Error : </b>{$error} <br /> <b>";
        $errormsg .= "MySQL Errno : </b>{$errorno} <br /><b>";
        $errormsg .= "File : </b>{$errorFile} <br /><b>";
        $errormsg .= "Lile : </b>{$errorLine} <br /><b> Message : </b> $message <br />";
        $msg = $errormsg;
        echo '<div style="font-size:12px;text-align:left; border:1px solid #9cc9e0; padding:1px 4px;color:#000000;font-family:Arial, Helvetica,sans-serif;"><span>' . $msg . '</span></div>';
        exit();
    } else {
        return false;
    }
}

/**
 *  数据库工厂类 phpcms
 */
final class CDbFactory {

    /**
     * 当前数据库工厂类静态实例
     */
    private static $db_factory;

    /**
     * 数据库配置列表
     */
    protected $db_config = array();

    /**
     * 数据库操作实例化列表
     */
    protected $db_list = array();
    private $table = array();
    private $db_setting = 'default';

    /**
     * 构造函数
     */
    public function __construct() {
        
    }

    /**
     * 返回当前终级类对象的实例
     * @param $db_config 数据库配置
     * @param $db_setting 
     * @return object
     */
    public static function getInstance($db_setting = 'default', $db_config = '') {
        $db_factory = null;
        if (!empty($db_config) && !isset($db_config[$db_setting])) {
            $db_setting = 'default';
        }
        if (self::$db_factory == '' || !is_object(self::$db_factory)) {
            self::$db_factory = $db_factory = new CDbFactory();
        } else {
            $db_factory = self::$db_factory;
        }
        if (empty($db_factory->db_config)) {
            if (empty($db_config)) {
                global $dbhost, $dbuser, $dbpassword, $dbname, $dbport, $debug;
                $db_config = [
                    'ms' => 'mysql',
                    'host' => $dbhost,
                    'prot' => empty($dbport) ? 3306 : $dbport,
                    'dbname' => $dbname,
                    'username' => $dbuser,
                    'password' => $dbpassword,
                    'debug' => $debug,
                    'options' => [
                        PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES 'utf8'",
                        PDO::ATTR_PERSISTENT => false,
                        PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
                        PDO::ATTR_CASE => PDO::CASE_NATURAL,
                    ],
                    'tablepre' => ''
                ];
            }
            self::$db_factory->db_config = $db_config;
        } else {
            if (!empty($db_config) && $db_config != $db_factory->db_config) {
                self::$db_factory->db_config = array_merge($db_config, $db_factory->db_config);
            }
        }
        return $db_factory;
    }

    /**
     * 获取数据库操作实例
     * @param $db_setting 数据库配置名称
     * @return CPDO
     */
    public function getDatabase($db_setting) {
        if (!empty($db_setting) && isset($this->db_config)) {
            
        } else {
            $db_setting = $this->db_config;
        }
        $object = null;
        if (!isset($this->db_list[$db_setting]) || !is_object($this->db_list[$db_setting])) {
            $object = new CPDO();
            $object->open($this->db_config);
            $object->connect();
            $this->db_list[$db_setting] = $object;
        } else {
            $object = $this->db_list[$db_setting];
        }
        return $object;
    }

    /**
     * 获取数据库配置信息
     * @param string $db_setting
     * @param bool $isAll  false单个$db_setting数据库配置(默认) ; true全部
     * @return array
     */
    public function getDbConfig($db_setting = 'default', $isAll = false) {
        $db_config = $this->db_config;
        if (!empty($db_setting) && isset($db_config[$db_setting])) {
            
        } else {
            $db_setting = $this->db_setting;
        }
        if (empty($db_config)) {
            global $dbhost, $dbuser, $dbpassword, $dbname, $dbport, $debug;
            $db_config = [
                'ms' => 'mysql',
                'host' => $dbhost,
                'prot' => empty($dbport) ? 3306 : $dbport,
                'dbname' => $dbname,
                'username' => $dbuser,
                'password' => $dbpassword,
                'debug' => $debug,
                'options' => [
                    PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES 'utf8'",
                    PDO::ATTR_PERSISTENT => false,
                    PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
                    PDO::ATTR_CASE => PDO::CASE_NATURAL,
                ],
                'tablepre' => ''
            ];
        }
        return $isAll ? $db_config : $db_config[$db_setting];
    }

    /**
     *  加载数据库驱动
     * @param $db_setting 	数据库配置名称
     * @return object
     */
    public function connect($db_setting) {
        $object = new CPDO();
        $object->open($this->db_config[$db_setting]);
        $object->connect();
        return $object;
    }

    /**
     * 关闭数据库连接
     * @return void
     */
    public function close() {
        if (is_array($this->db_list)) {
            foreach ($this->db_list as $db) {
                $db = null;
            }
            $this->db_list = null;
        }
    }

    /**
     * 析构函数
     */
    public function __destruct() {
        $this->close();
    }

}

/**
 *
 * @author Feng . Fox
 */
final class CPDOStatement {

    public $debug = false;
    public $pdo = null;
    private $st = null;

    /**
     * @param $st
     * @param bool $debug
     * @param $pdo
     */
    function __construct($st, $debug = true, $pdo) {
        $this->st = $st;
        $this->pdo = $pdo;
        $this->debug = $debug;
    }

    /**
     * @param array $input_parameters
     * @return $this|bool
     */
    public function execute(array $input_parameters = null) {
        try {
            $this->st->execute($input_parameters);
            return $this;
        } catch (PDOException $e) {
            halt($e, $this->debug);
            return false;
        }
    }

    /**
     * 输出1行数据
     * @param int $fetch_style
     * @return array
     */
    public function fetch($fetch_style = PDO::FETCH_ASSOC) {
        try {
            return $this->st->fetch($fetch_style);
        } catch (PDOException $e) {
            halt($e, $this->debug);
            return false;
        }
    }

    /**
     * @param $parameter
     * @param $variable
     * @param null $data_type
     * @param null $length
     * @param null $driver_options
     * @return $this|bool
     */
    public function bindParam($parameter, &$variable, $data_type = null, $length = null, $driver_options = null) {
        try {
            $this->st->bindParam($parameter, $variable, $data_type, $length, $driver_options);
            return $this;
        } catch (PDOException $e) {
            halt($e, $this->debug);
            return false;
        }
    }

    /**
     * @param $column
     * @param $param
     * @param null $type
     * @param null $maxlen
     * @param null $driverdata
     * @return $this|bool
     */
    public function bindColumn($column, &$param, $type = null, $maxlen = null, $driverdata = null) {
        try {
            $this->st->bindColumn($column, $param, $type, $maxlen, $driverdata);
            return $this;
        } catch (PDOException $e) {
            halt($e, $this->debug);
            return false;
        }
    }

    /**
     * 绑定参数
     *
     * @param string $parameter 字符参数[:num]或数字（从1开始）;根据prepare中的SQL语句
     * @param string $value 数据
     * @param int $data_type 其他
     * @return CPDOStatement boolean
     */
    public function bindValue($parameter, $value, $data_type = null) {
        try {
            $this->st->bindValue($parameter, $value, $data_type);
            return $this;
        } catch (PDOException $e) {
            halt($e, $this->debug);
            return false;
        }
    }

    /**
     * 总记录数
     * @return int
     */
    public function rowCount() {
        return $this->st->rowCount();
    }

    /**
     * 获取第一行的某列，默认第1列
     * @param int $column_number 从0开始
     * @return boolean
     */
    public function fetchColumn($column_number = null) {
        try {
            return $this->st->fetchColumn($column_number);
        } catch (PDOException $e) {
            halt($e, $this->debug);
            return false;
        }
    }

    /**
     * 输出全部数据
     * @param $fetch_style
     * @return array
     */
    public function fetchAll($fetch_style = PDO::FETCH_ASSOC) {
        try {
            return $this->st->fetchAll($fetch_style);
        } catch (PDOException $e) {
            halt($e, $this->debug);
            return false;
        }
    }

    /**
     * @param null $class_name
     * @param array $ctor_args
     * @return bool
     */
    public function fetchObject($class_name = null, array $ctor_args = null) {
        try {
            return $this->st->fetchObject($class_name, $ctor_args);
        } catch (PDOException $e) {
            halt($e, $this->debug);
            return false;
        }
    }

    /**
     * @return mixed
     */
    public function errorCode() {
        return $this->st->errorCode();
    }

    /**
     * @return mixed
     */
    public function errorInfo() {
        return $this->st->errorInfo();
    }

    /**
     * @param $attribute
     * @param $value
     * @return $this|bool
     */
    public function setAttribute($attribute, $value) {
        try {
            $this->st->setAttribute($attribute, $value);
            return $this;
        } catch (PDOException $e) {
            halt($e, $this->debug);
            return false;
        }
    }

    /**
     * @param $attribute
     * @return $this|bool
     */
    public function getAttribute($attribute) {
        try {
            $this->st->getAttribute($attribute);
            return $this;
        } catch (PDOException $e) {
            halt($e, $this->debug);
            return false;
        }
    }

    /*
     * 结果集列数
     */

    public function columnCount() {
        return $this->st->columnCount();
    }

    /**
     * @param $column
     * @return $this|bool
     */
    public function getColumnMeta($column) {
        try {
            $this->st->getColumnMeta($column);
            return $this;
        } catch (PDOException $e) {
            halt($e, $this->debug);
            return false;
        }
    }

    /**
     * @param $mode
     * @return $this|bool
     */
    public function setFetchMode($mode) {
        try {
            $this->st->setFetchMode($mode);
            return $this;
        } catch (PDOException $e) {
            halt($e, $this->debug);
            return false;
        }
    }

    /**
     * @return mixed
     */
    public function nextRowset() {
        return $this->st->nextRowset();
    }

    /**
     * @return mixed
     */
    public function closeCursor() {
        return $this->st->closeCursor();
    }

    /**
     * @return mixed
     */
    public function debugDumpParams() {
        return $this->st->debugDumpParams();
    }

    /**
     *
     */
    public function __destruct() {
        $this->closeCursor();
    }

}

/**
 * PDO
 * @author Feng . Fox 2013.11.11
 *
 */
final class CPDO {

    /**
     * 数据库配置信息
     */
    private $config = null;

    /**
     * 数据库连接资源句柄
     */
    public $pdo = null;
    protected $transactionCount = 0;

    public function __construct() {
        
    }

    /**
     * 打开数据库连接,有可能不真实连接数据库
     *
     * @param $config 数据库连接参数
     *            $config = [
     *            'ms' => 'mysql',
     *            'host' => 'localhost',
     *            'prot' => '3306'
     *            'dbname' => 'test',
     *            'username' => 'root',
     *            'password' => 'root',
     *            'debug' => true,
     *            'options'=>[
     *            PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES 'utf8'",
     *            PDO::ATTR_PERSISTENT => true,
     *            PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION
     *            ]
     *            ];
     * @return void
     */
    public function open($config) {
        $this->config = $config;
        if (isset($config ['autoconnect']) && $config ['autoconnect'] == 1) {
            $this->connect();
        }
    }

    /**
     * 真正开启数据库连接
     * @return void
     */
    public function connect() {
        try {
            if (empty($this->config ['dsn'])) {
                $dsn = "{$this->config['ms']}:host={$this->config['host']};dbname={$this->config['dbname']}";
                $dsn .= empty($this->config ['port']) ? '' : ';prot=' . $this->config ['port'];
            } else {
                $dsn = $this->config ['dsn'];
            }
            $this->pdo = new PDO($dsn, $this->config ['username'], $this->config ['password'], $this->config ['options']);
            $this->database = $this->config ['dbname'];
            return $this;
        } catch (PDOException $e) {
            halt($e, $this->config['debug'], '[PDOException] Can not connect to MySQL server');
            return false;
        }
    }

    /*
     * 标明回滚起始点
     */

    public function beginTransaction() {
        return $this->pdo->beginTransaction();
    }

    /*
     * 标明回滚结束点，并执行SQL
     */

    public function commit() {
        return $this->pdo->commit();
    }
                  
    public function inTransaction() {
        return $this->pdo->getAttribute(PDO::ATTR_AUTOCOMMIT);
    }
    /*
     * 获取错误码
     */

    public function errorCode() {
        return $this->pdo->errorCode();
    }

    /*
     * 获取错误的信息
     */

    public function errorInfo() {
        return $this->pdo->errorInfo();
    }

    /*
     * 处理一条SQL语句，并返回所影响的条目数
     */

    public function exec($sql) {
        try {
            return $this->pdo->exec($sql);
        } catch (PDOException $e) {
            halt($e, $this->config['debug']);
            return false;
        }
    }

    /*
     * 获取一个“数据库连接对象”的属性
     */

    public function getAttribute($attribute) {
        try {
            return $this->pdo->getAttribute($attribute);
        } catch (PDOException $e) {
            return false;
        }
    }

    /*
     * 获取有效的PDO驱动器名称
     */

    public function getAvailableDrivers() {
        return $this->pdo->getAvailableDrivers();
    }

    /*
     * 获取写入的最后一条数据的主键值
     */

    public function lastInsertId() {
        return $this->pdo->lastInsertId();
    }

    /**
     * 处理一条SQL语句 返回结果集
     *
     * @param string $sql
     * @return array
     */
    public function query($sql) {
        try {
            return $this->pdo->query($sql);
        } catch (PDOException $e) {
            halt($e, $this->config['debug']);
            return false;
        }
    }

    /**
     * 生成一个“查询对象”
     *
     * @param string $sql
     *            查询语句
     * @return CPDOStatement
     */
    public function prepare($sql) {
        try {
            return new CPDOStatement($this->pdo->prepare($sql), $this->config['debug'], $this->pdo);
        } catch (PDOException $e) {
            halt($e, $this->config['debug']);
            return false;
        }
    }

    /*
     * 为某个SQL中的字符串添加引号 public function quote(){ }
     */
    /*
     * 执行回滚
     */

    public function rollBack() {
        return $this->pdo->rollBack();
    }

    /*
     * 为一个“数据库连接对象”设定属性
     */

    public function setAttribute($attribute, $value) {
        try {
            $this->pdo->setAttribute($attribute, $value);
            return $this;
        } catch (PDOException $e) {
            return false;
        }
    }

    /**
     * 析构函数
     */
    public function __destruct() {
        $this->pdo = null;
    }

}

/**
 * 数据模型基类
 * @author Feng . Fox 2013.11.11
 */
class CDb {

    //数据库配置
    protected $db_config = '';
    //数据库连接
    protected $db;
    //调用数据库的配置项
    protected $db_setting = 'default';
    //数据表名
    protected $table_name = '';
    //表前缀
    protected $db_tablepre = '';
    //数据库
    protected $database = '';
    protected $Transactions = false;

    /** 配置
     * @param $table_name 表名称
     * @param string $db_setting 调用数据库配置项
     * @param array $db_config 数据库配置
     */
    public function __construct($table_name, $db_setting = 'default', $db_config = array()) {
        if (!empty($db_config) && !isset($db_config[$db_setting])) {
            $db_setting = 'default';
        }
        $this->db_setting = $db_setting;
        $dbf = CDbFactory::getInstance($db_setting, $db_config);
        //$this->db=$dbf->getDatabase($db_setting);
        $this->db_config = $dbf->getDbConfig($db_setting, true);
        //参数赋值
        $this->db_tablepre = $this->db_config['tablepre'];
        $this->database = $this->db_config['dbname'];
        $this->table_name = $this->db_tablepre . $table_name;
    }

    /**
     * 重置数据库连接参数
     * @param string $table_name
     * @param string $db_setting
     * @param array $db_config
     */
    public function ReSetDb($table_name = '', $db_setting = 'default', $db_config = array()) {
        if (!empty($db_config) && !isset($db_config[$db_setting])) {
            $db_setting = 'default';
        }
        $this->db_setting = $db_setting;
        $dbf = CDbFactory::getInstance($db_setting, $db_config);
        $this->db = $dbf->getDatabase($db_setting);
        $this->db_config = $dbf->getDbConfig($db_setting, true);
        //参数赋值
        $this->db_tablepre = $this->db_config[$db_setting]['tablepre'];
        $this->database = $this->db_config[$db_setting]['dbname'];
        if (!empty($table_name)) {
            $this->table_name = $this->db_tablepre . $table_name;
        }
    }

    /**
     * 设置 表名称，不包括前缀
     * @param $table_name
     * @return string
     */
    public function setTableName($table_name) {
        if (!empty($table_name)) {
            $this->table_name = $this->db_tablepre . $table_name;
        }
        return $this->table_name;
    }

    /**
     * 表名称，包括前缀
     * @return string
     */
    public function getTableName() {
        return $this->table_name;
    }

    /**
     * 表前缀
     * @return string
     */
    public function getTablePre() {
        return $this->db_tablepre;
    }

    /**
     * 当前数据库配置,默认当前数据库
     * @param string $db_setting
     * @param bool $isAll true 全部
     * @return string
     */
    public function getDbConfig($db_setting = '', $isAll = false) {
        if (empty($db_setting)) {
            $db_setting = $this->db_setting;
        }
        return $isAll ? $this->db_config : $this->db_config[$db_setting];
    }

    /** pdo 类
     * @return CPDO
     */
    final public function pdo() {
        if ($this->db != '' && is_object($this->db)) {
            return $this->db;
        }
        $this->db = $pdo = CDbFactory::getInstance($this->db_setting)->getDatabase($this->db_setting);
        return $pdo;
    }

    /**
     * 执行sql查询
     * @param $where 查询条件
     *                    字符串,请按照格式 ：
     *                        字符串 [例2：array('catid=:catid AND time>=:time ',array(':catid'=>10,':time'=>'2012-02-10')) ]
     *                        数组时 [例: array('name'=>'phpcms','password'=>'123456')]
     * @param $fields 需要查询的字段值[例`name`,`gender`,`birthday`]
     * @param $limit 返回结果范围[例：10或10,10 默认为空]
     * @param $order 排序方式    [默认按数据库默认方式排序]
     * @param $group 分组方式    [默认为空]
     * @return array        查询结果集数组
     */
    final public function select($where = '', $fields = '*', $limit = '', $order = '', $group = '') {
        $parameter = array();
        $search = '';
        if (!empty($where) && is_array($where)) {
            if (isset($where[1]) && is_array($where[1])) {
                list($a, $b) = $where;
                $search = $a;
                $i = 1;
                foreach ($b as $k => $r) {
                    $parameter[$i]['key'] = is_numeric($k) ? $i : $k;
                    $parameter[$i]['value'] = $r;
                    $i++;
                }
            } else {
                $i = 1;
                foreach ($where as $k => $r) {
                    if ($i > 1) {
                        $search .= " AND `$k`=:$k ";
                    } else {
                        $search .= " `$k`=:$k ";
                    }
                    $parameter[$i]['key'] = ':' . $k;
                    $parameter[$i]['value'] = $r;
                    $i++;
                }
            }
        } else {
            $search = $where;
        }
        $where = $search == '' ? '' : ' WHERE ' . $search;
        $order = $order == '' ? '' : ' ORDER BY ' . $order;
        $group = $group == '' ? '' : ' GROUP BY ' . $group;
        $limit = $limit == '' ? '' : ' LIMIT ' . $limit;
        $field = explode(',', $fields);
        array_walk($field, array($this, 'add_special_char'));
        $fields = implode(',', $field);

        $sql = 'SELECT ' . $fields . ' FROM ' . $this->databaseTable($this->table_name) . $where . $group . $order . $limit;
        $pdo = $this->pdo();
        $smt = $pdo->prepare($sql);
        if (is_array($parameter) && count($parameter) > 0)
            foreach ($parameter as $k => $r) {
                $smt->bindValue($r['key'], $r['value']);
            }
        $smt->execute();
        return $smt->fetchAll();
    }

    /**
     * 查询多条数据并分页
     * @param $where 查询条件
     *                    字符串,请按照格式 ：
     *                        字符串 [例2：array('catid=:catid AND time>=:time ',array(':catid'=>10,':time'=>'2012-02-10')) ]
     *                        数组时 [例: array('name'=>'phpcms','password'=>'123456')]
     * @param $fields 字段 *,id
     * @param $order 排序 id desc ,orderlist asc
     * @param $page 页码 1
     * @param $pagesize 每页条数
     * @param $setpages
     * @param $urlrule
     * @param $array
     * @return array
     */
    final public function listinfo($where = '', $fields = '*', $order = '', $page = 1, $pagesize = 20, $setpages = 10, $urlrule = '', $array = array()) {
        $parameter = array();
        $search = '';
        if (!empty($where) && is_array($where)) {
            if (isset($where[1]) && is_array($where[1])) {
                list($a, $b) = $where;
                $search = $a;
                $i = 1;
                foreach ($b as $k => $r) {
                    $parameter[$i]['key'] = is_numeric($k) ? $i : $k;
                    $parameter[$i]['value'] = $r;
                    $i++;
                }
            } else {
                $i = 1;
                foreach ($where as $k => $r) {
                    if ($i > 1) {
                        $search .= " AND `$k`=:$k ";
                    } else {
                        $search .= " `$k`=:$k ";
                    }
                    $parameter[$i]['key'] = ':' . $k;
                    $parameter[$i]['value'] = $r;
                    $i++;
                }
            }
        } else {
            $search = $where;
        }
        $where = $search == '' ? '' : ' WHERE ' . $search;
        $order = $order == '' ? '' : ' ORDER BY ' . $order;
        $group = '';
        $group = $group == '' ? '' : ' GROUP BY ' . $group;
        $page = max(intval($page), 1);
        $offset = $pagesize * ($page - 1);
        $limit = " LIMIT $offset,$pagesize";
        $fields = empty($fields) ? '*' : $fields;
        $field = explode(',', $fields);
        array_walk($field, array($this, 'add_special_char'));
        $fields = implode(',', $field);

        $sql = 'SELECT sql_calc_found_rows ' . $fields . ' FROM ' . $this->databaseTable($this->table_name) . $where . $group . $order . $limit;
        $pdo = $this->pdo();
        $smt = $pdo->prepare($sql);
        if (is_array($parameter) && count($parameter) > 0)
            foreach ($parameter as $k => $r) {
                $smt->bindValue($r['key'], $r['value']);
            }
        $smt->execute();
        $smt2 = $pdo->prepare("SELECT FOUND_ROWS()");
        $smt2->execute();
        $this->number = $smt2->fetchColumn();
        if ($this->number > 0) {
            $this->pages = pages($this->number, $page, $pagesize, $urlrule, $array, $setpages);
            return $smt->fetchAll();
        }
        return array();
    }

    /**
     * 获取单条记录查询
     * @param array $where 查询条件语句
     *                    字符串,请按照格式 ：
     *                        字符串 [例2：array('catid=:catid AND time>=:time ',array(':catid'=>10,':time'=>'2012-02-10')) ]
     *                        数组时 [例: array('name'=>'phpcms','password'=>'123456')]
     * @param string $fields 需要查询的字段值[例`name`,`gender`,`birthday`]
     * @param string $order 排序方式    [默认按数据库默认方式排序]
     * @param string $group 分组方式    [默认为空]
     * @return array/null    数据查询结果集,如果不存在，则返回空
     */
    final public function get_one($where, $fields = '*', $order = '', $group = '') {
        $parameter = array();
        $search = '';
        if (is_array($where)) {
            //$where第2个参数为数组
            if (isset($where[1]) && is_array($where[1])) {
                $search = $where[0];
                $i = 1;
                foreach ($where[1] as $k => $r) {
                    $parameter[$i]['key'] = is_numeric($k) ? $i : $k;
                    $parameter[$i]['value'] = $r;
                    $i++;
                }
            } else {
                $i = 1;
                foreach ($where as $k => $r) {
                    if ($i > 1) {
                        $search .= " AND `$k`=:$k ";
                    } else {
                        $search .= " `$k`=:$k ";
                    }
                    $parameter[$i]['key'] = ':' . $k;
                    $parameter[$i]['value'] = $r;
                    $i++;
                }
            }
        } else {
            $search = $where;
        }
        $where = $search == '' ? '' : ' WHERE ' . $search;
        $order = $order == '' ? '' : ' ORDER BY ' . $order;
        $group = $group == '' ? '' : ' GROUP BY ' . $group;
        $limit = ' LIMIT 1';
        $field = explode(',', $fields);
        array_walk($field, array($this, 'add_special_char'));
        $fields = implode(',', $field);

        $sql = 'SELECT ' . $fields . ' FROM ' . $this->databaseTable($this->table_name) . $where . $group . $order . $limit;
        $pdo = $this->pdo();
        $smt = $pdo->prepare($sql);
        foreach ($parameter as $k => $r) {
            $smt->bindValue($r['key'], $r['value']);
        }
        $smt->execute();
        return $smt->fetch();
    }

    /**
     * 直接执行sql查询
     * @param $sql 查询sql语句
     * @return    boolean/query resource        如果为查询语句，返回资源句柄，否则返回true/false
     */
    final public function query($sql) {
        return $this->pdo()->query($sql);
    }

    /**
     * 直接执行sql查询
     * @param $sql 查询sql语句
     * @return int|false
     */
    final public function exec($sql) {
        return $this->pdo()->exec($sql);
    }

    /**
     * 执行添加记录操作
     * @param array $data 要增加的数据，参数为数组。数组key为字段值，数组值为数据取值
     * @param bool $return_insert_id 是否返回新建ID号
     * @param bool $replace 是否采用 replace into的方式添加数据
     * @return boolean
     */
    final public function insert($data, $return_insert_id = false, $replace = false) {
        if (!is_array($data) || count($data) == 0) {
            return false;
        }
        $fields = array_keys($data);
        $valuedata = array_values($data);
        array_walk($fields, array($this, 'add_special_char'));

        $field = implode(',', $fields);
        $value = str_repeat('?,', count($fields) - 1) . '?';

        $cmd = $replace ? 'REPLACE INTO' : 'INSERT INTO';
        $sql = $cmd . $this->databaseTable($this->table_name) . ' (' . $field . ') VALUES (' . $value . ')';
        $pdo = $this->pdo();
        $smt = $pdo->prepare($sql);
        $i = 1;
        foreach ($valuedata as $r) {
            $smt->bindValue($i, empty($r) ? '' : $r);
            $i++;
        }
        $row = $smt->execute();
        return $return_insert_id ? $pdo->lastInsertId() : $row;
    }

    /**
     * 获取最后一次添加记录的主键号
     * @return int
     */
    final public function insert_id() {
        return $this->pdo()->lastInsertId();
    }

    /**
     * 执行更新记录操作
     * @param $data 要更新的数据内容，参数为数组
     *                        为数组时数组key为字段值，数组值为数据取值
     *                        为数组时[例: array('name'=>'lanmps','password'=>'123456')]
     *                        数组的另一种使用array('name'=>'+=1', 'base'=>'-=1');程序会自动解析为`name` = `name` + 1, `base` = `base` - 1
     *                        字符串,请按照格式 ：
     *                        字符串 [例2：array('catid=:catid AND time>=:time ',array(':catid'=>10,':time'=>'2012-02-10')) ]
     * @param $where 更新数据时的条件,
     *                        字符串,请按照格式 ：
     *                        字符串 [例2：array('catid=:catid AND time>=:time ',array(':catid'=>10,':time'=>'2012-02-10')) ]
     *                        数组时 [例: array('name'=>'lanmps','password'=>'123456')]
     * @return boolean
     */
    final public function update($data, $where) {
        $parameter = array();
        $i = $j = 1;
        $field = '';
        if (is_array($data)) {
            $fields = array();
            foreach ($data as $k => $v) {
                switch (substr($v, 0, 2)) {
                    case '+=':
                        $v = substr($v, 2);
                        if (is_numeric($v)) {
                            $fields[] = self::add_special_char($k) . '=' . self::add_special_char($k) . '+' . self::escape_string($v, '', false);
                        } else {
                            continue;
                        }

                        break;
                    case '-=':
                        $v = substr($v, 2);
                        if (is_numeric($v)) {
                            $fields[] = self::add_special_char($k) . '=' . self::add_special_char($k) . '-' . self::escape_string($v, '', false);
                        } else {
                            continue;
                        }
                        break;
                    default:
                        $fields[] = self::add_special_char($k) . '=:' . $k;
                        $parameter[$i]['key'] = ':' . $k;
                        $parameter[$i]['value'] = $v;
                        $i++;
                }
            }
            $field = implode(',', $fields);
        } else {
            $field = $data;
        }
        $search = '';
        if (is_array($where)) {
            //$where第2个参数为数组
            if (isset($where[1]) && is_array($where[1])) {
                $search = $where[0];
                //$i++;
                foreach ($where[1] as $k => $r) {
                    $parameter[$i]['key'] = is_numeric($k) ? $i : $k;
                    $parameter[$i]['value'] = $r;
                    $i++;
                }
            } else {
                //$i++;
                $x = 1;
                foreach ($where as $k => $r) {
                    if ($x > 1) {
                        $search .= " AND `$k`=:$k ";
                    } else {
                        $search .= " `$k`=:$k ";
                    }
                    $parameter[$i]['key'] = ':' . $k;
                    $parameter[$i]['value'] = $r;
                    $i++;
                    $x++;
                }
            }
        } else {
            $search = $where;
        }
        $where = ' WHERE ' . $search;
        $sql = 'UPDATE ' . $this->databaseTable($this->table_name) . ' SET ' . $field . $where;
        $pdo = $this->pdo();
        $smt = $pdo->prepare($sql);
        foreach ($parameter as $r) {
            $smt->bindValue($r['key'], $r['value']);
        }
        return $smt->execute();
    }

    /**
     * 执行删除记录操作
     * @param $where 删除数据条件,不充许为空。
     * @return boolean
     */
    final public function delete($where) {
        if (!is_array($where) || count($where) == 0) {
            return false;
        }
        $parameter = array();
        $search = '';
        if (is_array($where)) {
            //$where第2个参数为数组
            if (isset($where[1]) && is_array($where[1])) {
                $search = $where[0];
                $i = 1;
                foreach ($where[1] as $k => $r) {
                    $parameter[$i]['key'] = is_numeric($k) ? $i : $k;
                    $parameter[$i]['value'] = $r;
                    $i++;
                }
            } else {
                $i = 1;
                foreach ($where as $k => $r) {
                    if ($i > 1) {
                        $search .= " AND `$k`=:$k ";
                    } else {
                        $search .= " `$k`=:$k ";
                    }
                    $parameter[$i]['key'] = ':' . $k;
                    $parameter[$i]['value'] = $r;
                    $i++;
                }
            }
        } else {
            $search = $where;
        }
        $where = $search == '' ? '' : ' WHERE ' . $search;
        $sql = 'DELETE FROM ' . $this->databaseTable($this->table_name) . $where;
        $pdo = $this->pdo();
        $smt = $pdo->prepare($sql);
        foreach ($parameter as $k => $r) {
            $smt->bindValue($r['key'], $r['value']);
        }
        return $smt->execute();
    }

    /**
     * 计算记录数
     * @param string /array $where 查询条件
     */
    final public function count($where = '') {
        $r = self::get_one($where, "COUNT(*) AS num");
        return $r['num'];
    }

    /**
     * 将数组转换为SQL语句
     * @param array $where 要生成的数组
     * @param string $font 连接串。
     * @return string
     */
    final public function sqls($where, $font = ' AND ') {
        if (is_array($where)) {
            $sql = '';
            foreach ($where as $key => $val) {
                $sql .= $sql ? " $font `$key` = '$val' " : " `$key` = '$val'";
            }
            return $sql;
        } else {
            return $where;
        }
    }

    /**
     * 获取数据表主键
     * @return array
     */
    final public function get_primary() {
        return self::$db->get_primary($this->table_name);
    }

    /**
     * 获取表字段
     * @param string $table_name 表名
     * @param bool true默认加前缀,false不加前缀
     * @return array
     */
    final public function get_fields($table_name = '', $isTablepre = true) {
        if (empty($table_name)) {
            $table_name = $this->table_name;
        } else {
            $table_name = ($isTablepre ? $this->db_tablepre : '') . $table_name;
        }
        $fields = array();
        $pdo = $this->pdo();
        $smt = $pdo->prepare("SHOW COLUMNS FROM $table_name");
        $smt->execute();
        while ($r = $smt->fetch()) {
            $fields[$r['Field']] = $r['Type'];
        }
        return $fields;
    }

    /**
     * 检查表是否存在
     * @param $table 表名
     * @return boolean
     */
    final public function table_exists($table) {
        $tables = $this->list_tables();
        return in_array($this->db_tablepre . $table, $tables) ? 1 : 0;
    }

    /**
     * 检查字段是否存在
     * @param $field 字段名
     * @return boolean
     */
    public function field_exists($field) {
        $fields = $this->db->get_fields($this->table_name);
        return array_key_exists($field, $fields);
    }

    /*     * 获取数据库中的所有表
     * @return array
     */

    final public function list_tables() {
        $tables = array();
        $pdo = $this->pdo();
        $smt = $pdo->prepare("SHOW TABLES");
        $smt->execute();
        while ($r = $smt->fetch()) {
            $tables[] = $r['Tables_in_' . $this->database];
        }
        return $tables;
    }

    /**
     * 返回数据结果集
     * @return array
     */
    final private function fetch_array() {
        
    }

    /**
     * 返回数据库版本号
     */
    final public function version() {
        return $this->db->version();
    }

    final private function databaseTable($table) {
        if (!empty($this->db_tablepre) && strpos($table, $this->db_tablepre) !== 0) {
            $table = $this->db_tablepre . $table;
        }
        return " `{$this->database}`.`{$table}` ";
    }

    /**
     * 对字段两边加反引号，以保证数据库安全
     * @param $value 数组值
     * @return string
     */
    final public static function add_special_char($value) {
        if ('*' == $value || false !== strpos($value, '(') || false !== strpos($value, '.') || false !== strpos($value, '`')) {
            //不处理包含* 或者 使用了sql方法。
        } else {
            $value = '`' . trim($value) . '`';
        }
        if (preg_match('/\b(select|insert|update|delete)\b/i', $value)) {
            $value = preg_replace('/\b(select|insert|update|delete)\b/i', '', $value);
        }
        return $value;
    }

    /**
     * 对字段值两边加引号，以保证数据库安全
     * @param $value 数组值
     * @param $key 数组key
     * @param $quotation
     * @return string
     */
    final public static function escape_string(&$value, $key = '', $quotation = 1) {
        if ($quotation) {
            $q = '\'';
        } else {
            $q = '';
        }
        $value = $q . $value . $q;
        return $value;
    }

    /**
     * 获取单条记录查询
     * @param array $sql 查询条件语句
     * @return array/null    数据查询结果集,如果不存在，则返回空
     */
    final public function fetch($sql) {
        $pdo = $this->pdo();
        $smt = $pdo->prepare($sql);
        $smt->execute();
        return $smt->fetch();
    }

    /**
     * 执行sql查询
     * @param $sql 查询条件
     * @return array    查询结果集数组
     */
    final public function fetchAll($sql = '') {
        $pdo = $this->pdo();
        $smt = $pdo->prepare($sql);
        $smt->execute();
        return $smt->fetchAll();
    }

    /*     * 第一个参数值
     * @param $sql
     * @return mixed
     */

    final public function resultFirst($sql) {
        $pdo = $this->pdo();
        $smt = $pdo->prepare($sql);
        $smt->execute();
        return $smt->fetchColumn();
    }

    final public function beginTransaction() {
        if ($this->Transactions == false) {
            $this->pdo()->beginTransaction();
            $this->Transactions = true;
        }
        return true;
    }

    final public function commit() {
        if ($this->Transactions == true) {
            if ($this->pdo()->beginTransaction()) {
                $this->Transactions = false;
            }
        }
        return true;
    }
    
    final public function inTransaction() {
        return $this->pdo()->inTransaction();
    }

    public function rollBack() {
        if ($this->Transactions == true) {
            if ($this->pdo()->rollBack()) {
                $this->Transactions = false;
            }
        }
        return true;
    }

    /**
     * 析构函数
     */
    public function __destruct() {
        $dbf = CDbFactory::getInstance();
        $dbf->close();
        $this->db = null;
    }

}
